using System;
using System.IO;
using System.Net;
using System.Web;

namespace Pegasus.Web
{
	/// <summary>
	/// This class provide a way to forward a request to a differnt URL and capture the response and
	/// and copy the response from the given URL.
	/// </summary>
	public static class WebForwarder
	{
		/// <summary>
		/// Forwards the specified request.
		/// </summary>
		/// <param name="request">The request.</param>
		/// <param name="forwardUrl">The forward URL.</param>
		/// <param name="response">The response.</param>
		public static void Forward( HttpRequest request, Uri forwardUrl, HttpResponse response )
		{
			// Setup forwarding request
			HttpWebRequest forwardRequest = GetForwardingRequest( request, forwardUrl );

			WebResponse forwardResponse = null;
			try
			{
				forwardResponse = forwardRequest.GetResponse();
			}
			catch( WebException e )
			{
				forwardResponse = e.Response;
			}

			CopyResponse( forwardResponse, response );
		}

		/// <summary>
		/// Gets the forwarding request.
		/// </summary>
		/// <param name="request">The request.</param>
		/// <param name="forwardUrl">The forward URL.</param>
		/// <returns></returns>
		private static HttpWebRequest GetForwardingRequest( HttpRequest request, Uri forwardUrl )
		{
			HttpWebRequest forwardRequest = (HttpWebRequest) HttpWebRequest.Create( forwardUrl );

			forwardRequest.ContentLength = request.ContentLength;
			forwardRequest.ContentType = request.ContentType;
			if( request.Cookies.Count > 0 )
			{
				forwardRequest.CookieContainer = new CookieContainer();
				foreach( String inCookieName in request.Cookies )
				{
					HttpCookie inCookie = request.Cookies[ inCookieName ];
					Cookie outCookie = new Cookie( inCookie.Name, inCookie.Value, inCookie.Path, forwardRequest.RequestUri.Authority );
					outCookie.Expires = inCookie.Expires;

					forwardRequest.CookieContainer.Add( outCookie );
				}
			}

			forwardRequest.Method = request.HttpMethod;
			forwardRequest.UserAgent = request.UserAgent;

			int length = request.ContentLength;
			byte[] buffer = new byte[ length ];

			if( forwardRequest.Method == "POST" )
			{
				request.InputStream.Read( buffer, 0, length );
				forwardRequest.GetRequestStream().Write( buffer, 0, length );
			}

			return forwardRequest;
		}

		/// <summary>
		/// Copies the response.
		/// </summary>
		/// <param name="forwardResponse">The forward response.</param>
		/// <param name="response">The response.</param>
		private static void CopyResponse( WebResponse forwardResponse, HttpResponse response )
		{
			response.ContentType = forwardResponse.ContentType;
			using( Stream stream = forwardResponse.GetResponseStream() )
			{
				byte[] buffer = new byte[ 4096 ];
				int bytesRead = stream.Read( buffer, 0, 4096 );
				while( bytesRead > 0 )
				{
					response.BinaryWrite( buffer );
					bytesRead = stream.Read( buffer, 0, 4096 );
				}
			}
		}
	}
}
